package com.thinkdit.lib.util;

import android.os.AsyncTask;

import com.alibaba.fastjson.JSON;
import com.thinkdit.lib.base.IRequestCallback;
import com.thinkdit.lib.base.ResultModelBase;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by QiuDa on 15/11/28.
 */
public class HttpUtils<T extends ResultModelBase> {
    private final static String DATE_FORMAT = "yyyyMMddHHmmss";
    private final List<String> mRequestLit = Collections.synchronizedList(new ArrayList());
    private static final String TAG = "HttpUtils";
    private OkHttpClient client = new OkHttpClient();
    private ExecutorService LIMITED_TASK_EXECUTOR = Executors.newFixedThreadPool(7);

    public HttpUtils() {

    }

    /**
     * 请求处理
     *
     * @param callBack
     * @param request  request对象
     * @return ResultModel
     */
    private final T processRequest(IRequestCallback<T> callBack, Request request) {
        String url = request.url().url().toString();
        T resultModel = null;
        try {
            resultModel = getClazz().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        if (resultModel == null) {
            mRequestLit.remove(url);
            return null;
        }
        try {
            resultModel.setUrl(url);
            Response response = client.newCall(request).execute();
            if (response == null) {
                resultModel.setCode(ResultModelBase.ERROR_CODE_RESULT);
                resultModel.setException(new Exception("网络异常，请检查网络连接"));
                resultModel.setMessage("网络异常，请检查网络连接");
                return resultModel;
            }
            String resultjson = response.body().string();
            L.d(TAG, "processRequest-response  " + url + "\n  __RESULT:  " + resultjson);
            if (response.code() == 200) {
                if (!StringUtil.isNullorEmpty(resultjson)) {
                    try {
                        resultModel = JSON.parseObject(resultjson, getClazz());
                        resultModel.setUrl(url);
                    } catch (Exception e) {
                        L.e(TAG, e);
                        resultModel.setException(e);
                        resultModel.setMessage("网络异常，请检查网络连接");
                        resultModel.setCode(ResultModelBase.ERROR_CODE_PARSE);
                    }
                } else {
                    resultModel.setCode(ResultModelBase.ERROR_CODE_RESULT + response.code());
                }
            } else {
                resultModel.setException(new Exception("网络异常，请检查网络连接"));
                resultModel.setMessage("网络异常，请检查网络连接");
                resultModel.setCode(ResultModelBase.ERROR_CODE_REQUEST + response.code());
            }

            if (ResultModelBase.SUCCESS_CODE.equals(resultModel.getCode())) {
                if (null != callBack) {
                    Object obj = callBack.asyncExecute(url, resultModel);
                    resultModel.setDataModel(obj);
                }
            }
        } catch (IOException e) {
            L.e(TAG, e);
            if (!StringUtil.isNullorEmpty(e.getMessage()) && e.getMessage().equals("Canceled")) {
                return resultModel;
            }
            resultModel.setCode(ResultModelBase.ERROR_CODE_CONNECT);
            resultModel.setException(new Exception("网络异常，请检查网络连接"));
            resultModel.setMessage("网络异常，请检查网络连接");
        } catch (Exception e1) {
            L.e(TAG, e1);
            resultModel.setCode(null);
            resultModel.setCode(ResultModelBase.ERROR_CODE_PARSE);
            resultModel.setException(new Exception("网络异常，请检查网络连接"));
            resultModel.setMessage("网络异常，请检查网络连接");
        }
        return resultModel;
    }

    /**
     * 处理请求结果
     *
     * @param resultModel 请求结果
     */
    private void processResult(IRequestCallback<T> callback, T resultModel) {
        if (null == callback) {
            return;
        }
        if (resultModel.getException() != null) {
            callback.onError(resultModel.getUrl(), resultModel.getException());
        }
        try {
            if (ResultModelBase.SUCCESS_CODE.equals(resultModel.getCode())) {
                callback.onSucceed(resultModel.getUrl(), resultModel);
            } else {
                callback.onFailure(resultModel.getUrl(), resultModel);
            }
        } catch (Exception e) {
            L.e(TAG, e);
            callback.onError(resultModel.getUrl(), new Exception("网络异常，请检查网络连接"));
        }
    }


    /**
     * get
     *
     * @param url    url
     * @param header 头
     * @param tag    tag
     * @return 是否发起请求
     */
    public final boolean get(IRequestCallback<T> callBack, String url, Map<String, String> header, Object tag) {
        if (mRequestLit.contains(url)) {
            L.d(TAG, "cancel url request... " + url);
            return false;
        }
        mRequestLit.add(url);

        Request.Builder builder
                = new Request.Builder()
                .url(url).tag(tag);
        if (header != null) {
            for (String key : header.keySet()) {
                builder.addHeader(key, header.get(key));
            }
        }

        HttpAsync async = new HttpAsync(url, callBack);
        async.executeOnExecutor(LIMITED_TASK_EXECUTOR, builder.build());
        return true;
    }


    /**
     * Post方法
     *
     * @param url         请求url
     * @param requestBody 请求body
     * @param header      头
     * @param tag         tag
     * @return 结果
     */
    public final boolean post(IRequestCallback<T> callBack, String url, RequestBody requestBody,
                              Map<String, String> header, Object tag) {
        if (mRequestLit.contains(url)) {
            L.d(TAG, "cancel url request... " + url);
            return false;
        }
        mRequestLit.add(url);

        Request.Builder builder = new Request.Builder()
                .url(url).tag(tag)
                .post(requestBody);

        if (header != null) {
            for (String key : header.keySet()) {
                builder.addHeader(key, header.get(key));
            }
        }

        HttpAsync async = new HttpAsync(url, callBack);
        async.executeOnExecutor(LIMITED_TASK_EXECUTOR, builder.build());
        return true;
    }

    class HttpAsync extends AsyncTask<Request, Integer, T> {
        private String mUrl;
        private IRequestCallback<T> mCallback;

        public HttpAsync(String url, IRequestCallback<T> callBack) {
            mCallback = callBack;
            mUrl = url;
        }

        @Override
        protected T doInBackground(Request... params) {
            if (mCallback == null || params == null || params.length == 0) {
                return null;
            }
            return processRequest(mCallback, params[0]);
        }

        @Override
        protected void onPostExecute(T result) {
            if (result != null) {
                processResult(mCallback, result);
                if (StringUtil.isNullorEmpty(mUrl)) {
                    return;
                }
                for (String url : mRequestLit) {
                    if (mUrl.equals(url)) {
                        mRequestLit.remove(url);
                        break;
                    }
                }
            }
        }
    }


    public Class<T> getClazz() {
        Type t = getClass().getGenericSuperclass();
        ParameterizedType p = (ParameterizedType) t;
        Class<T> c = (Class<T>) p.getActualTypeArguments()[0];
        return c;
    }

}
